From 0e480fbe65d991944707b2f8b648e0f1102c40c0 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 23 Feb 2006 14:43:45 +0100 Subject: [PATCH] Clean up segment selector fixup and validation. Signed-off-by: Keir Fraser --- xen/arch/x86/domain.c | 21 +++++++-------------- xen/arch/x86/traps.c | 6 +----- xen/arch/x86/x86_32/mm.c | 20 +++++++------------- xen/arch/x86/x86_32/traps.c | 12 ++++++++---- xen/arch/x86/x86_64/mm.c | 17 ++++++----------- xen/common/elf.c | 1 - xen/include/asm-x86/desc.h | 35 ++++++++++++++++++++--------------- 7 files changed, 49 insertions(+), 63 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 21ef47f0ce..ee0bada316 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -349,27 +349,19 @@ int arch_set_info_guest( unsigned long phys_basetab = INVALID_MFN; int i, rc; - /* - * This is sufficient! If the descriptor DPL differs from CS RPL then we'll - * #GP. If DS, ES, FS, GS are DPL 0 then they'll be cleared automatically. - * If SS RPL or DPL differs from CS RPL then we'll #GP. - */ if ( !(c->flags & VGCF_HVM_GUEST) ) { - if ( !VALID_STACKSEL(c->user_regs.ss) || - !VALID_STACKSEL(c->kernel_ss) || - !VALID_CODESEL(c->user_regs.cs) ) - return -EINVAL; + fixup_guest_selector(c->user_regs.ss); + fixup_guest_selector(c->kernel_ss); + fixup_guest_selector(c->user_regs.cs); #ifdef __i386__ - if ( !VALID_CODESEL(c->event_callback_cs) || - !VALID_CODESEL(c->failsafe_callback_cs) ) - return -EINVAL; + fixup_guest_selector(c->event_callback_cs); + fixup_guest_selector(c->failsafe_callback_cs); #endif for ( i = 0; i < 256; i++ ) - if ( !VALID_CODESEL(c->trap_ctxt[i].cs) ) - return -EINVAL; + fixup_guest_selector(c->trap_ctxt[i].cs); } else if ( !hvm_enabled ) return -EINVAL; @@ -383,6 +375,7 @@ int arch_set_info_guest( v->arch.flags |= TF_kernel_mode; memcpy(&v->arch.guest_context, c, sizeof(*c)); + init_int80_direct_trap(v); if ( !(c->flags & VGCF_HVM_GUEST) ) { diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index a9a0ff10b2..d331d7d72a 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1430,11 +1430,7 @@ long do_set_trap_table(struct trap_info *traps) if ( cur.address == 0 ) break; - if ( !VALID_CODESEL(cur.cs) ) - { - rc = -EPERM; - break; - } + fixup_guest_selector(cur.cs); memcpy(&dst[cur.vector], &cur, sizeof(cur)); diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index 2bcb57f8b4..f622498922 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -223,8 +223,7 @@ long do_stack_switch(unsigned long ss, unsigned long esp) int nr = smp_processor_id(); struct tss_struct *t = &init_tss[nr]; - if ( !VALID_STACKSEL(ss) ) - return -EPERM; + fixup_guest_selector(ss); current->arch.guest_context.kernel_ss = ss; current->arch.guest_context.kernel_sp = esp; @@ -239,7 +238,7 @@ int check_descriptor(struct desc_struct *d) { unsigned long base, limit; u32 a = d->a, b = d->b; - u16 cs = a>>16; + u16 cs; /* A not-present descriptor will always fault, so is safe. */ if ( !(b & _SEGMENT_P) ) @@ -272,17 +271,12 @@ int check_descriptor(struct desc_struct *d) if ( (b & _SEGMENT_TYPE) != 0xc00 ) goto bad; - /* Can't allow far jump to a Xen-private segment. */ - if ( !VALID_CODESEL(cs) ) + /* Validate and fix up the target code selector. */ + cs = a >> 16; + fixup_guest_selector(cs); + if ( !guest_gate_selector_okay(cs) ) goto bad; - - /* - * VALID_CODESEL might have fixed up the RPL for us. So be sure to - * update the descriptor. - * - */ - d->a &= 0x0000ffff; - d->a |= cs<<16; + a = d->a = (d->a & 0xffffU) | (cs << 16); /* Reserved bits must be zero. */ if ( (b & 0xe0) != 0 ) diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index 5d23bea594..51c8e9b7de 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -254,10 +254,14 @@ void init_int80_direct_trap(struct vcpu *v) /* * We can't virtualise interrupt gates, as there's no way to get - * the CPU to automatically clear the events_mask variable. + * the CPU to automatically clear the events_mask variable. Also we + * must ensure that the CS is safe to poke into an interrupt gate. */ - if ( TI_GET_IF(ti) ) + if ( TI_GET_IF(ti) || !guest_gate_selector_okay(ti->cs) ) + { + v->arch.int80_desc.a = v->arch.int80_desc.b = 0; return; + } v->arch.int80_desc.a = (ti->cs << 16) | (ti->address & 0xffff); v->arch.int80_desc.b = @@ -274,8 +278,8 @@ long do_set_callbacks(unsigned long event_selector, { struct vcpu *d = current; - if ( !VALID_CODESEL(event_selector) || !VALID_CODESEL(failsafe_selector) ) - return -EPERM; + fixup_guest_selector(event_selector); + fixup_guest_selector(failsafe_selector); d->arch.guest_context.event_callback_cs = event_selector; d->arch.guest_context.event_callback_eip = event_address; diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index f783cce7e6..ee45c2a875 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -292,7 +292,7 @@ long do_set_segment_base(unsigned int which, unsigned long base) int check_descriptor(struct desc_struct *d) { u32 a = d->a, b = d->b; - u16 cs = a>>16; + u16 cs; /* A not-present descriptor will always fault, so is safe. */ if ( !(b & _SEGMENT_P) ) @@ -314,17 +314,12 @@ int check_descriptor(struct desc_struct *d) if ( (b & _SEGMENT_TYPE) != 0xc00 ) goto bad; - /* Can't allow far jump to a Xen-private segment. */ - if ( !VALID_CODESEL(cs) ) + /* Validate and fix up the target code selector. */ + cs = a >> 16; + fixup_guest_selector(cs); + if ( !guest_gate_selector_okay(cs) ) goto bad; - - /* - * VALID_CODESEL might have fixed up the RPL for us. So be sure to - * update the descriptor. - * - */ - d->a &= 0x0000ffff; - d->a |= cs<<16; + a = d->a = (d->a & 0xffffU) | (cs << 16); /* Reserved bits must be zero. */ if ( (b & 0xe0) != 0 ) diff --git a/xen/common/elf.c b/xen/common/elf.c index 4fc8f26ecd..412acae01a 100644 --- a/xen/common/elf.c +++ b/xen/common/elf.c @@ -61,7 +61,6 @@ int parseelfimage(struct domain_setup_info *dsi) continue; guestinfo = elfbase + shdr->sh_offset; - printk("Xen-ELF header found: '%s'\n", guestinfo); if ( (strstr(guestinfo, "LOADER=generic") == NULL) && (strstr(guestinfo, "GUEST_OS=linux") == NULL) ) diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h index 793413f56a..7208c04ce0 100644 --- a/xen/include/asm-x86/desc.h +++ b/xen/include/asm-x86/desc.h @@ -26,23 +26,28 @@ #define GUEST_KERNEL_RPL 1 #endif +/* Fix up the RPL of a guest segment selector. */ +#define fixup_guest_selector(sel) \ + ((sel) = (((sel) & 3) >= GUEST_KERNEL_RPL) ? (sel) : \ + (((sel) & ~3) | GUEST_KERNEL_RPL)) + /* - * Guest OS must provide its own code selectors, or use the one we provide. Any - * LDT selector value is okay. Note that checking only the RPL is insufficient: - * if the selector is poked into an interrupt, trap or call gate then the RPL - * is ignored when the gate is accessed. + * We need this function because enforcing the correct guest kernel RPL is + * unsufficient if the selector is poked into an interrupt, trap or call gate. + * The selector RPL is ignored when a gate is accessed. We must therefore make + * sure that the selector does not reference a Xen-private segment. + * + * Note that selectors used only by IRET do not need to be checked. If the + * descriptor DPL fiffers from CS RPL then we'll #GP. + * + * Stack and data selectors do not need to be checked. If DS, ES, FS, GS are + * DPL < CPL then they'll be cleared automatically. If SS RPL or DPL differs + * from CS RPL then we'll #GP. */ -#define VALID_SEL(_s) \ - (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || ((_s)&4)) && \ - (((_s)&3) == GUEST_KERNEL_RPL)) -#define VALID_CODESEL(_s) ({ \ - if ( ((_s) & 3) == 0 ) \ - (_s) |= GUEST_KERNEL_RPL; \ - (_s) == FLAT_KERNEL_CS || VALID_SEL(_s); }) -#define VALID_STACKSEL(_s) ({ \ - if ( ((_s) & 3) == 0 ) \ - (_s) |= GUEST_KERNEL_RPL; \ - (_s) == FLAT_KERNEL_SS || VALID_SEL(_s); }) +#define guest_gate_selector_okay(sel) \ + ((((sel)>>3) < FIRST_RESERVED_GDT_ENTRY) || /* Guest seg? */ \ + ((sel) == FLAT_KERNEL_CS) || /* Xen default seg? */ \ + ((sel) & 4)) /* LDT seg? */ /* These are bitmasks for the high 32 bits of a descriptor table entry. */ #define _SEGMENT_TYPE (15<< 8) -- 2.30.2